#include <jni.h>
#include <string>
#include <thread>
#include <atomic>
#include <mutex>
#include <chrono>
#include <android/log.h>

// Linux CAN相关头文件
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <cstring>

#define LOG_TAG "CanNative"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)

// 错误码定义
#define SUCCESS 0
#define ERROR_INIT_FAILED -1
#define ERROR_CONNECT_FAILED -2
#define ERROR_SEND_FAILED -3
#define ERROR_RECEIVE_FAILED -4
#define ERROR_INVALID_PARAM -5
#define ERROR_DEVICE_NOT_FOUND -6
#define ERROR_PERMISSION_DENIED -7
#define ERROR_ALREADY_CONNECTED -8
#define ERROR_NOT_CONNECTED -9

// 状态码定义
#define STATUS_DISCONNECTED 0
#define STATUS_CONNECTED 1
#define STATUS_ERROR 2

// 全局变量
static int can_socket = -1;
static std::atomic<bool> is_receiving(false);
static std::thread receive_thread;
static std::mutex socket_mutex;
static JavaVM* g_jvm = nullptr;
static jobject g_callback_obj = nullptr;
static jmethodID g_data_callback_method = nullptr;
static jmethodID g_status_callback_method = nullptr;
static char g_device_path[32] = "can0"; // 保存设备路径

// JNI回调函数
void callJavaDataCallback(JNIEnv* env, int canId, jbyteArray data, int dataLength, 
                         jboolean isExtended, jlong timestamp) {
    if (g_callback_obj && g_data_callback_method) {
        env->CallStaticVoidMethod(
            env->FindClass("com/automotive/can1939/jni/CanNativeInterface"),
            g_data_callback_method,
            canId, data, dataLength, isExtended, timestamp
        );
    }
}

void callJavaStatusCallback(JNIEnv* env, int status, jstring message) {
    if (g_callback_obj && g_status_callback_method) {
        env->CallStaticVoidMethod(
            env->FindClass("com/automotive/can1939/jni/CanNativeInterface"),
            g_status_callback_method,
            status, message
        );
    }
}

// CAN接收线程函数
void receiveThreadFunction() {
    JNIEnv* env;
    if (g_jvm->AttachCurrentThread(&env, nullptr) != JNI_OK) {
        LOGE("Failed to attach thread to JVM");
        return;
    }
    
    struct can_frame frame;
    
    while (is_receiving.load()) {
        std::lock_guard<std::mutex> lock(socket_mutex);
        
        if (can_socket < 0) {
            break;
        }
        
        // 设置超时
        fd_set readfds;
        struct timeval timeout;
        FD_ZERO(&readfds);
        FD_SET(can_socket, &readfds);
        timeout.tv_sec = 0;
        timeout.tv_usec = 100000; // 100ms超时
        
        int ret = select(can_socket + 1, &readfds, nullptr, nullptr, &timeout);
        if (ret > 0 && FD_ISSET(can_socket, &readfds)) {
            ssize_t nbytes = read(can_socket, &frame, sizeof(struct can_frame));
            
            if (nbytes == sizeof(struct can_frame)) {
                // 创建Java字节数组
                jbyteArray dataArray = env->NewByteArray(frame.can_dlc);
                env->SetByteArrayRegion(dataArray, 0, frame.can_dlc, 
                                      reinterpret_cast<jbyte*>(frame.data));
                
                // 获取当前时间戳
                jlong timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(
                    std::chrono::system_clock::now().time_since_epoch()).count();
                
                // 判断是否为扩展帧
                jboolean isExtended = (frame.can_id & CAN_EFF_FLAG) ? JNI_TRUE : JNI_FALSE;
                
                // 清除标志位，获取纯CAN ID
                int canId = frame.can_id & (isExtended ? CAN_EFF_MASK : CAN_SFF_MASK);
                
                // 调用Java回调
                callJavaDataCallback(env, canId, dataArray, frame.can_dlc, 
                                   isExtended, timestamp);
                
                env->DeleteLocalRef(dataArray);
            }
        } else if (ret < 0 && errno != EINTR) {
            LOGE("Select error: %s", strerror(errno));
            break;
        }
    }
    
    g_jvm->DetachCurrentThread();
}

extern "C" {

// JNI_OnLoad函数
jint JNI_OnLoad(JavaVM* vm, void* reserved) {
    g_jvm = vm;
    JNIEnv* env;
    
    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
        return JNI_ERR;
    }
    
    // 获取回调方法ID
    jclass clazz = env->FindClass("com/automotive/can1939/jni/CanNativeInterface");
    if (clazz) {
        g_data_callback_method = env->GetStaticMethodID(clazz, 
            "onCanDataReceivedFromNative", "(I[BIZJ)V");
        g_status_callback_method = env->GetStaticMethodID(clazz, 
            "onCanStatusChangedFromNative", "(ILjava/lang/String;)V");
    }
    
    return JNI_VERSION_1_6;
}

// 初始化CAN接口
JNIEXPORT jint JNICALL
Java_com_automotive_can1939_jni_CanNativeInterface_initCan(JNIEnv *env, jclass clazz,
                                                           jstring devicePath, jint baudRate) {
    const char* path = env->GetStringUTFChars(devicePath, nullptr);
    
    LOGI("Initializing CAN interface: %s, baudrate: %d", path, baudRate);
    
    // 保存设备路径
    strncpy(g_device_path, path, sizeof(g_device_path) - 1);
    g_device_path[sizeof(g_device_path) - 1] = '\0';
    
    // 创建socket
    can_socket = socket(PF_CAN, SOCK_RAW, CAN_RAW);
    if (can_socket < 0) {
        LOGE("Failed to create CAN socket: %s", strerror(errno));
        env->ReleaseStringUTFChars(devicePath, path);
        return ERROR_INIT_FAILED;
    }
    
    // 获取接口索引
    struct ifreq ifr;
    strcpy(ifr.ifr_name, path);
    if (ioctl(can_socket, SIOCGIFINDEX, &ifr) < 0) {
        LOGE("Failed to get interface index: %s", strerror(errno));
        close(can_socket);
        can_socket = -1;
        env->ReleaseStringUTFChars(devicePath, path);
        return ERROR_DEVICE_NOT_FOUND;
    }
    
    env->ReleaseStringUTFChars(devicePath, path);
    
    LOGI("CAN interface initialized successfully");
    return SUCCESS;
}

// 连接CAN总线
JNIEXPORT jint JNICALL
Java_com_automotive_can1939_jni_CanNativeInterface_connectCan(JNIEnv *env, jclass clazz) {
    if (can_socket < 0) {
        return ERROR_NOT_CONNECTED;
    }
    
    struct sockaddr_can addr;
    struct ifreq ifr;
    
    // 重新获取接口索引
    strcpy(ifr.ifr_name, g_device_path);
    if (ioctl(can_socket, SIOCGIFINDEX, &ifr) < 0) {
        LOGE("Failed to get interface index: %s", strerror(errno));
        return ERROR_CONNECT_FAILED;
    }
    
    // 绑定socket到CAN接口
    addr.can_family = AF_CAN;
    addr.can_ifindex = ifr.ifr_ifindex;
    
    if (bind(can_socket, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
        LOGE("Failed to bind CAN socket: %s", strerror(errno));
        return ERROR_CONNECT_FAILED;
    }
    
    LOGI("CAN connected successfully");
    return SUCCESS;
}

// 断开CAN连接
JNIEXPORT jint JNICALL
Java_com_automotive_can1939_jni_CanNativeInterface_disconnectCan(JNIEnv *env, jclass clazz) {
    std::lock_guard<std::mutex> lock(socket_mutex);
    
    if (can_socket >= 0) {
        close(can_socket);
        can_socket = -1;
        LOGI("CAN disconnected");
    }
    
    return SUCCESS;
}

// 发送CAN帧
JNIEXPORT jint JNICALL
Java_com_automotive_can1939_jni_CanNativeInterface_sendCanFrame(JNIEnv *env, jclass clazz,
                                                               jint canId, jbyteArray data,
                                                               jint dataLength, jboolean isExtended) {
    if (can_socket < 0) {
        return ERROR_NOT_CONNECTED;
    }
    
    if (dataLength > 8) {
        return ERROR_INVALID_PARAM;
    }
    
    struct can_frame frame;
    memset(&frame, 0, sizeof(frame));
    
    // 设置CAN ID和标志
    frame.can_id = canId;
    if (isExtended) {
        frame.can_id |= CAN_EFF_FLAG;
    }
    
    // 设置数据长度
    frame.can_dlc = dataLength;
    
    // 复制数据
    jbyte* dataBytes = env->GetByteArrayElements(data, nullptr);
    memcpy(frame.data, dataBytes, dataLength);
    env->ReleaseByteArrayElements(data, dataBytes, JNI_ABORT);
    
    // 发送帧
    std::lock_guard<std::mutex> lock(socket_mutex);
    ssize_t nbytes = write(can_socket, &frame, sizeof(frame));
    
    if (nbytes != sizeof(frame)) {
        LOGE("Failed to send CAN frame: %s", strerror(errno));
        return ERROR_SEND_FAILED;
    }
    
    return SUCCESS;
}

// 启动接收
JNIEXPORT jint JNICALL
Java_com_automotive_can1939_jni_CanNativeInterface_startReceiving(JNIEnv *env, jclass clazz) {
    if (can_socket < 0) {
        return ERROR_NOT_CONNECTED;
    }
    
    if (is_receiving.load()) {
        return SUCCESS; // 已经在接收
    }
    
    is_receiving.store(true);
    receive_thread = std::thread(receiveThreadFunction);
    
    LOGI("Started CAN receiving");
    return SUCCESS;
}

// 停止接收
JNIEXPORT jint JNICALL
Java_com_automotive_can1939_jni_CanNativeInterface_stopReceiving(JNIEnv *env, jclass clazz) {
    is_receiving.store(false);
    
    if (receive_thread.joinable()) {
        receive_thread.join();
    }
    
    LOGI("Stopped CAN receiving");
    return SUCCESS;
}

// 设置过滤器
JNIEXPORT jint JNICALL
Java_com_automotive_can1939_jni_CanNativeInterface_setCanFilter(JNIEnv *env, jclass clazz,
                                                               jint filterId, jint mask) {
    if (can_socket < 0) {
        return ERROR_NOT_CONNECTED;
    }
    
    struct can_filter filter;
    filter.can_id = filterId;
    filter.can_mask = mask;
    
    if (setsockopt(can_socket, SOL_CAN_RAW, CAN_RAW_FILTER,
                   &filter, sizeof(filter)) < 0) {
        LOGE("Failed to set CAN filter: %s", strerror(errno));
        return ERROR_INIT_FAILED;
    }
    
    return SUCCESS;
}

// 获取状态
JNIEXPORT jint JNICALL
Java_com_automotive_can1939_jni_CanNativeInterface_getCanStatus(JNIEnv *env, jclass clazz) {
    if (can_socket < 0) {
        return STATUS_DISCONNECTED;
    }
    return STATUS_CONNECTED;
}

// 释放资源
JNIEXPORT jint JNICALL
Java_com_automotive_can1939_jni_CanNativeInterface_releaseCan(JNIEnv *env, jclass clazz) {
    // 停止接收
    Java_com_automotive_can1939_jni_CanNativeInterface_stopReceiving(env, clazz);
    
    // 断开连接
    Java_com_automotive_can1939_jni_CanNativeInterface_disconnectCan(env, clazz);
    
    LOGI("CAN resources released");
    return SUCCESS;
}

} // extern "C"